using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HslCommunication.BasicFramework;
using HslCommunication.Core;
using HslCommunication.Core.Address;
using HslCommunication.Core.Net;

namespace HslCommunication.Profinet.Melsec
{
	/// <summary>
	/// 三菱PLC通讯类，采用UDP的协议实现，采用Qna兼容3E帧协议实现，需要在PLC侧先的以太网模块先进行配置，必须为二进制通讯<br />
	/// Mitsubishi PLC communication class is implemented using UDP protocol and Qna compatible 3E frame protocol. 
	/// The Ethernet module needs to be configured first on the PLC side, and it must be binary communication.
	/// </summary>
	/// <remarks>
	/// <inheritdoc cref="T:HslCommunication.Profinet.Melsec.MelsecMcNet" path="remarks" />
	/// </remarks>
	/// <example>
	/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\melsecTest.cs" region="Usage" title="简单的短连接使用" />
	/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\melsecTest.cs" region="Usage2" title="简单的长连接使用" />
	/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\melsecTest.cs" region="ReadExample1" title="基本的读取示例" />
	/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\melsecTest.cs" region="ReadExample2" title="批量读取示例" />
	/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\melsecTest.cs" region="ReadExample3" title="随机字读取示例" />
	/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\melsecTest.cs" region="ReadExample4" title="随机批量字读取示例" />
	/// </example>
	public class MelsecMcUdp : NetworkUdpDeviceBase
	{
		/// <inheritdoc cref="P:HslCommunication.Profinet.Melsec.MelsecMcNet.NetworkNumber" />
		public byte NetworkNumber
		{
			get;
			set;
		} = 0;


		/// <inheritdoc cref="P:HslCommunication.Profinet.Melsec.MelsecMcNet.NetworkStationNumber" />
		public byte NetworkStationNumber
		{
			get;
			set;
		} = 0;


		/// <inheritdoc cref="M:HslCommunication.Profinet.Melsec.MelsecMcNet.#ctor" />
		public MelsecMcUdp()
		{
			base.WordLength = 1;
			base.ByteTransform = new RegularByteTransform();
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Melsec.MelsecMcNet.#ctor(System.String,System.Int32)" />
		public MelsecMcUdp(string ipAddress, int port)
		{
			base.WordLength = 1;
			IpAddress = ipAddress;
			Port = port;
			base.ByteTransform = new RegularByteTransform();
		}

		/// <inheritdoc />
		protected virtual OperateResult<McAddressData> McAnalysisAddress(string address, ushort length)
		{
			return McAddressData.ParseMelsecFrom(address, length);
		}

		/// <inheritdoc />
		public override OperateResult<byte[]> Read(string address, ushort length)
		{
			OperateResult<McAddressData> operateResult = McAnalysisAddress(address, length);
			if (!operateResult.IsSuccess)
			{
				return OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			List<byte> list = new List<byte>();
			ushort num = 0;
			while (num < length)
			{
				ushort num2 = (ushort)Math.Min(length - num, 900);
				operateResult.Content.Length = num2;
				OperateResult<byte[]> operateResult2 = ReadAddressData(operateResult.Content);
				if (!operateResult2.IsSuccess)
				{
					return operateResult2;
				}
				list.AddRange(operateResult2.Content);
				num = (ushort)(num + num2);
				if (operateResult.Content.McDataType.DataType == 0)
				{
					operateResult.Content.AddressStart += num2;
				}
				else
				{
					operateResult.Content.AddressStart += num2 * 16;
				}
			}
			return OperateResult.CreateSuccessResult(list.ToArray());
		}

		private OperateResult<byte[]> ReadAddressData(McAddressData addressData)
		{
			byte[] mcCore = MelsecHelper.BuildReadMcCoreCommand(addressData, isBit: false);
			OperateResult<byte[]> operateResult = ReadFromCoreServer(MelsecMcNet.PackMcCommand(mcCore, NetworkNumber, NetworkStationNumber));
			if (!operateResult.IsSuccess)
			{
				return OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			OperateResult operateResult2 = MelsecMcNet.CheckResponseContent(operateResult.Content);
			if (!operateResult2.IsSuccess)
			{
				return OperateResult.CreateFailedResult<byte[]>(operateResult2);
			}
			return MelsecMcNet.ExtractActualData(SoftBasic.ArrayRemoveBegin(operateResult.Content, 11), isBit: false);
		}

		/// <inheritdoc />
		public override OperateResult Write(string address, byte[] value)
		{
			OperateResult<McAddressData> operateResult = McAnalysisAddress(address, 0);
			if (!operateResult.IsSuccess)
			{
				return OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			return WriteAddressData(operateResult.Content, value);
		}

		private OperateResult WriteAddressData(McAddressData addressData, byte[] value)
		{
			byte[] mcCore = MelsecHelper.BuildWriteWordCoreCommand(addressData, value);
			OperateResult<byte[]> operateResult = ReadFromCoreServer(MelsecMcNet.PackMcCommand(mcCore, NetworkNumber, NetworkStationNumber));
			if (!operateResult.IsSuccess)
			{
				return operateResult;
			}
			OperateResult operateResult2 = MelsecMcNet.CheckResponseContent(operateResult.Content);
			if (!operateResult2.IsSuccess)
			{
				return operateResult2;
			}
			return OperateResult.CreateSuccessResult();
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Melsec.MelsecMcNet.ReadRandom(System.String[])" />
		public OperateResult<byte[]> ReadRandom(string[] address)
		{
			McAddressData[] array = new McAddressData[address.Length];
			for (int i = 0; i < address.Length; i++)
			{
				OperateResult<McAddressData> operateResult = McAddressData.ParseMelsecFrom(address[i], 1);
				if (!operateResult.IsSuccess)
				{
					return OperateResult.CreateFailedResult<byte[]>(operateResult);
				}
				array[i] = operateResult.Content;
			}
			byte[] mcCore = MelsecHelper.BuildReadRandomWordCommand(array);
			OperateResult<byte[]> operateResult2 = ReadFromCoreServer(MelsecMcNet.PackMcCommand(mcCore, NetworkNumber, NetworkStationNumber));
			if (!operateResult2.IsSuccess)
			{
				return OperateResult.CreateFailedResult<byte[]>(operateResult2);
			}
			OperateResult operateResult3 = MelsecMcNet.CheckResponseContent(operateResult2.Content);
			if (!operateResult3.IsSuccess)
			{
				return OperateResult.CreateFailedResult<byte[]>(operateResult3);
			}
			return MelsecMcNet.ExtractActualData(SoftBasic.ArrayRemoveBegin(operateResult2.Content, 11), isBit: false);
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Melsec.MelsecMcNet.ReadRandom(System.String[],System.UInt16[])" />
		public OperateResult<byte[]> ReadRandom(string[] address, ushort[] length)
		{
			if (length.Length != address.Length)
			{
				return new OperateResult<byte[]>(StringResources.Language.TwoParametersLengthIsNotSame);
			}
			McAddressData[] array = new McAddressData[address.Length];
			for (int i = 0; i < address.Length; i++)
			{
				OperateResult<McAddressData> operateResult = McAddressData.ParseMelsecFrom(address[i], length[i]);
				if (!operateResult.IsSuccess)
				{
					return OperateResult.CreateFailedResult<byte[]>(operateResult);
				}
				array[i] = operateResult.Content;
			}
			byte[] mcCore = MelsecHelper.BuildReadRandomCommand(array);
			OperateResult<byte[]> operateResult2 = ReadFromCoreServer(MelsecMcNet.PackMcCommand(mcCore, NetworkNumber, NetworkStationNumber));
			if (!operateResult2.IsSuccess)
			{
				return OperateResult.CreateFailedResult<byte[]>(operateResult2);
			}
			OperateResult operateResult3 = MelsecMcNet.CheckResponseContent(operateResult2.Content);
			if (!operateResult3.IsSuccess)
			{
				return OperateResult.CreateFailedResult<byte[]>(operateResult3);
			}
			return MelsecMcNet.ExtractActualData(SoftBasic.ArrayRemoveBegin(operateResult2.Content, 11), isBit: false);
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Melsec.MelsecMcNet.ReadRandomInt16(System.String[])" />
		public OperateResult<short[]> ReadRandomInt16(string[] address)
		{
			OperateResult<byte[]> operateResult = ReadRandom(address);
			if (!operateResult.IsSuccess)
			{
				return OperateResult.CreateFailedResult<short[]>(operateResult);
			}
			return OperateResult.CreateSuccessResult(base.ByteTransform.TransInt16(operateResult.Content, 0, address.Length));
		}

		/// <inheritdoc />
		public override OperateResult<bool[]> ReadBool(string address, ushort length)
		{
			OperateResult<McAddressData> operateResult = McAnalysisAddress(address, length);
			if (!operateResult.IsSuccess)
			{
				return OperateResult.CreateFailedResult<bool[]>(operateResult);
			}
			byte[] mcCore = MelsecHelper.BuildReadMcCoreCommand(operateResult.Content, isBit: true);
			OperateResult<byte[]> operateResult2 = ReadFromCoreServer(MelsecMcNet.PackMcCommand(mcCore, NetworkNumber, NetworkStationNumber));
			if (!operateResult2.IsSuccess)
			{
				return OperateResult.CreateFailedResult<bool[]>(operateResult2);
			}
			OperateResult operateResult3 = MelsecMcNet.CheckResponseContent(operateResult2.Content);
			if (!operateResult3.IsSuccess)
			{
				return OperateResult.CreateFailedResult<bool[]>(operateResult3);
			}
			OperateResult<byte[]> operateResult4 = MelsecMcNet.ExtractActualData(SoftBasic.ArrayRemoveBegin(operateResult2.Content, 11), isBit: true);
			if (!operateResult4.IsSuccess)
			{
				return OperateResult.CreateFailedResult<bool[]>(operateResult4);
			}
			return OperateResult.CreateSuccessResult(operateResult4.Content.Select((byte m) => m == 1).Take(length).ToArray());
		}

		/// <inheritdoc />
		public override OperateResult Write(string address, bool[] values)
		{
			OperateResult<McAddressData> operateResult = McAnalysisAddress(address, 0);
			if (!operateResult.IsSuccess)
			{
				return operateResult;
			}
			byte[] mcCore = MelsecHelper.BuildWriteBitCoreCommand(operateResult.Content, values);
			OperateResult<byte[]> operateResult2 = ReadFromCoreServer(MelsecMcNet.PackMcCommand(mcCore, NetworkNumber, NetworkStationNumber));
			if (!operateResult2.IsSuccess)
			{
				return operateResult2;
			}
			OperateResult operateResult3 = MelsecMcNet.CheckResponseContent(operateResult2.Content);
			if (!operateResult3.IsSuccess)
			{
				return operateResult3;
			}
			return OperateResult.CreateSuccessResult();
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Melsec.MelsecMcNet.RemoteRun" />
		public OperateResult RemoteRun()
		{
			OperateResult<byte[]> operateResult = ReadFromCoreServer(MelsecMcNet.PackMcCommand(new byte[8]
			{
				1,
				16,
				0,
				0,
				1,
				0,
				0,
				0
			}, NetworkNumber, NetworkStationNumber));
			if (!operateResult.IsSuccess)
			{
				return operateResult;
			}
			OperateResult operateResult2 = MelsecMcNet.CheckResponseContent(operateResult.Content);
			if (!operateResult2.IsSuccess)
			{
				return operateResult2;
			}
			return OperateResult.CreateSuccessResult();
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Melsec.MelsecMcNet.RemoteStop" />
		public OperateResult RemoteStop()
		{
			OperateResult<byte[]> operateResult = ReadFromCoreServer(MelsecMcNet.PackMcCommand(new byte[6]
			{
				2,
				16,
				0,
				0,
				1,
				0
			}, NetworkNumber, NetworkStationNumber));
			if (!operateResult.IsSuccess)
			{
				return operateResult;
			}
			OperateResult operateResult2 = MelsecMcNet.CheckResponseContent(operateResult.Content);
			if (!operateResult2.IsSuccess)
			{
				return operateResult2;
			}
			return OperateResult.CreateSuccessResult();
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Melsec.MelsecMcNet.RemoteReset" />
		public OperateResult RemoteReset()
		{
			OperateResult<byte[]> operateResult = ReadFromCoreServer(MelsecMcNet.PackMcCommand(new byte[6]
			{
				6,
				16,
				0,
				0,
				1,
				0
			}, NetworkNumber, NetworkStationNumber));
			if (!operateResult.IsSuccess)
			{
				return operateResult;
			}
			OperateResult operateResult2 = MelsecMcNet.CheckResponseContent(operateResult.Content);
			if (!operateResult2.IsSuccess)
			{
				return operateResult2;
			}
			return OperateResult.CreateSuccessResult();
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Melsec.MelsecMcNet.ReadPlcType" />
		public OperateResult<string> ReadPlcType()
		{
			OperateResult<byte[]> operateResult = ReadFromCoreServer(MelsecMcNet.PackMcCommand(new byte[4]
			{
				1,
				1,
				0,
				0
			}, NetworkNumber, NetworkStationNumber));
			if (!operateResult.IsSuccess)
			{
				return OperateResult.CreateFailedResult<string>(operateResult);
			}
			OperateResult operateResult2 = MelsecMcNet.CheckResponseContent(operateResult.Content);
			if (!operateResult2.IsSuccess)
			{
				return OperateResult.CreateFailedResult<string>(operateResult2);
			}
			return OperateResult.CreateSuccessResult(Encoding.ASCII.GetString(operateResult.Content, 11, 16).TrimEnd());
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Melsec.MelsecMcNet.ErrorStateReset" />
		public OperateResult ErrorStateReset()
		{
			OperateResult<byte[]> operateResult = ReadFromCoreServer(MelsecMcNet.PackMcCommand(new byte[4]
			{
				23,
				22,
				0,
				0
			}, NetworkNumber, NetworkStationNumber));
			if (!operateResult.IsSuccess)
			{
				return operateResult;
			}
			OperateResult operateResult2 = MelsecMcNet.CheckResponseContent(operateResult.Content);
			if (!operateResult2.IsSuccess)
			{
				return operateResult2;
			}
			return OperateResult.CreateSuccessResult();
		}

		/// <inheritdoc />
		public override string ToString()
		{
			return $"MelsecMcUdp[{IpAddress}:{Port}]";
		}
	}
}
